package secondary.vo;



import org.hibernate.Session;
import org.hibernate.exception.ViolatedConstraintNameExtracter;


import ontology.VOOntology;
import ontology.actions.general.GetCase;
import ontology.actions.general.GetCases;
import ontology.actions.general.InformCase;
import ontology.actions.general.Log;
import ontology.actions.general.ParseCases;
import ontology.actions.general.ReturnList;
import ontology.actions.general.ReturnParseCases;
import ontology.actions.vo.InformVOOutcome;
import ontology.actions.vo.VOIndex;
import ontology.concepts.general.DBQueryRules;
import ontology.concepts.general.ICase;
import ontology.concepts.vo.VOCase;
import ontology.concepts.vo.VOLog;
import ontology.concepts.vo.VONorm;
import ontology.concepts.vo.VOObligation;
import ontology.concepts.vo.VOOutcome;
import utils.DBUtils;
import utils.HibernateUtil;

import classes.UMCourtAgent;
import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.onto.UngroundedException;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.DFService;
import jade.lang.acl.ACLMessage;
import jade.util.leap.ArrayList;

public class DatabaseVO extends UMCourtAgent {
	
	private Codec codec = new SLCodec();
	private Ontology ontology = VOOntology.getInstance();
	private Session session;
	
	@Override
	protected void setup() 
	{
		System.out.println(getDate()+ ": "+this.getLocalName()+" agent is now running...");
		registerAgent((String)getArguments()[0]);
		
		// Register language and ontology
	    getContentManager().registerLanguage(codec);
	    getContentManager().registerOntology(ontology);
		
	    session = HibernateUtil.getSessionFactory().openSession();
		System.out.println(getDate()+" : Connected to Database");
		
		this.addBehaviour(new receiveBehaviour());
	}
	
	
	@Override
	protected void takeDown()
	{
		System.out.println(getDate()+": "+this.getLocalName() +" is de-registering...");
		try {
			DFService.deregister(this);
			session.close();
		}
        catch (Exception e) {}
	}
	
	class receiveBehaviour extends CyclicBehaviour
	{
		@Override
		public void action() 
		{
			ACLMessage msg = null;
			while((msg = blockingReceive())==null)
				;
	        	ContentElement content;
				try {
					content = getContentManager().extractContent(msg);
					Concept action = ((Action) content).getAction();
					switch (msg.getPerformative()) 
			        {
			        case (ACLMessage.REQUEST):
			        	if (action instanceof ParseCases)
				        {
				        	content = getContentManager().extractContent(msg);
				            ParseCases pc = (ParseCases)((Action)content).getAction();
				            
				            ReturnParseCases rpc = parseCases(pc);
				            
				            ACLMessage reply = new ACLMessage(ACLMessage.INFORM);
				            reply.setLanguage(codec.getName());
				            reply.setOntology(ontology.getName());
				            reply.setConversationId(msg.getConversationId());
							
							try 
							{
								getContentManager().fillContent(reply, new Action(msg.getSender(), rpc));
								reply.addReceiver(msg.getSender());
								send(reply);
							}
							catch (Exception ex) { ex.printStackTrace(); }
				        }		        	
			        	if (action instanceof VOIndex)
				        {
				        	content = getContentManager().extractContent(msg);
				            VOIndex i = (VOIndex)((Action)content).getAction();
				           
				            index(i);
				        }
			        	if (action instanceof Log)
			        	{
			        		content = getContentManager().extractContent(msg);
				            Log l = (Log)((Action)content).getAction();
				            log(l, msg.getSender());
				        }
			        	if (action instanceof GetCases)
			        	{
			        		content = getContentManager().extractContent(msg);
				            GetCases<Integer> gcs = (GetCases<Integer>)((Action)content).getAction();
				            ReturnList rl = getCases(gcs);
//				        	myprintln("Cases returned: "+rl.getList().size());
				            //Return List of cases
				        	ACLMessage reply = new ACLMessage(ACLMessage.INFORM);
							reply.setLanguage(codec.getName());
							reply.setOntology(ontology.getName());
							reply.setConversationId(msg.getConversationId());
							try 
							{
								getContentManager().fillContent(reply, new Action(msg.getSender(), rl));
								reply.addReceiver(msg.getSender());
								send(reply);
							}
							catch (Exception ex) { ex.printStackTrace(); }
				            
			        	}
			        	if (action instanceof GetCase)
			        	{
			        		content = getContentManager().extractContent(msg);
			        		String id = ((GetCase)((Action)content).getAction()).getId();
			        		
			        		InformCase ic = getCase(id);
			        		//return the case
			    		    ACLMessage reply = new ACLMessage(ACLMessage.INFORM);
			    			reply.setLanguage(codec.getName());
			    			reply.setOntology(ontology.getName());
			    			try 
			    			{
			    				getContentManager().fillContent(reply, new Action(msg.getSender(), ic));
			    				reply.addReceiver(msg.getSender());
			    				send(reply);
			    			}
			    			catch (Exception ex) { ex.printStackTrace(); }							
			        	}
			        	break;
			        case ACLMessage.INFORM :
			        	content = getContentManager().extractContent(msg);
			        	if(content instanceof InformVOOutcome){
			        		InformVOOutcome vocase = (InformVOOutcome) content;
			        		if(vocase.getOutcome()!=null)
			        			DBUtils.saveOrUpdate(vocase.getOutcome());
			        	}
			        	if(content instanceof InformCase){
			        		InformCase vocase = (InformCase) content;
			        		if(vocase.getC()!=null)
			        			DBUtils.saveOrUpdate(vocase.getC());
			        	}
			        }					
				} catch (UngroundedException e) {
					e.printStackTrace();
				} catch (CodecException e) {
					e.printStackTrace();
				} catch (OntologyException e) {
					e.printStackTrace();
				}
		}
		
		private ReturnParseCases parseCases(ParseCases pc){

            ArrayList caseids = (ArrayList) pc.getCaseids();
            ArrayList cases = new ArrayList();
            for (int i=0;i<caseids.size();i++)
            {
            	String id = (String) caseids.get(i);
            	ICase c = DBUtils.getVOCase(id);
            	cases.add(c);
            }
            
            ReturnParseCases rpc = new ReturnParseCases();
            rpc.setList(cases);
            return rpc;
		}
		
		private void index(VOIndex index){
            if(index.getVOOutcomes()!=null){
            	for (int i = 0; i < index.getVOOutcomes().size(); i++) {
    				VOOutcome out = (VOOutcome) index.getVOOutcomes().get(i);
                	DBUtils.saveOrUpdate(out);
    			}
            }
		}
		
		private void log(Log log, AID sender){
			VOLog l = new VOLog();
			l.setMessage(log.getMessage());
			l.setSender(sender.getLocalName());
			l.setTime(log.getTime());
			DBUtils.saveVOLog(l);
		}
		
		private ReturnList getCases(GetCases<Integer> gcs){
			
            VOCase newCase = (VOCase) gcs.getC();
            DBQueryRules r = gcs.getR();
            VOObligation violation = newCase.getViolation();
            VONorm norm = newCase.getNorm();
            java.util.List<VOCase> cases;
            if(r.getDepth().equalsIgnoreCase("contract-type")){
            	cases = DBUtils.getVOCasesByContractType(norm);
            }else 
            	if(r.getDepth().equalsIgnoreCase("norm")){
            	cases = DBUtils.getVOCasesByNorm(norm);
            	}
            	else{
            		cases = DBUtils.getVOCasesByNormAction(violation.getVoaction().getName());
            	}
            //get norms addressed by vo
            ArrayList all = new ArrayList();
            for(Object o : cases)
            	all.add(o);
        	ReturnList rl = new ReturnList();        	
        	rl.setList(all);
        	return rl;            
		}
		
		private InformCase getCase(String  id){
		    VOCase c = (VOCase) DBUtils.getVOCase(id);
		    InformCase ic = new InformCase();
		    ic.setC(c);
		    return ic;
		}
	}
}
	
